#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <semaphore.h>
#include <pthread.h> 
#include <time.h>

#include "od_def.h"
#include "od_trace.h"
#include "od_task.h"
#include "od_tube.h"
#include "od_os.h"
#include "od_msg.h"
#include "od_os_config.h"
#include "od_engine.h"
#include "od_sip_event_distributor.h"
#include "od_sip_comn.h"


#define MODULE_NAME "sip-event-distributor"
#define SIP_EVENT_DISTRIBUTOR_TSK_STACK_SIZE  (4*1024 * 1024)   /*线程栈资源大小*/


typedef struct sip_event_queue_link
{
    od_sip_event_queue evt_que;
    struct sip_event_queue_link *next;
}sip_event_queue_link_t;

typedef struct 
{
    TASK_COMMON_MEMBERS

    od_sip_ctx *ctx;
    
    struct {
        int num;
        OD_MUTEX_ID mux; 
        sip_event_queue_link_t *que;
    }evt_que_link;
}od_sip_evt_dstrb_obj;

static od_sip_evt_dstrb_obj *obj_ptr = NULL;


int od_sip_evt_distrb_add(od_sip_event_queue *evt_que)
{
    sip_event_queue_link_t *node = NULL;
    
    OD_SIP_ASSERT_RETURN(evt_que && obj_ptr, OD_ERROR);

    od_mutex_lock(&obj_ptr->evt_que_link.mux); 
    node = (sip_event_queue_link_t *)od_malloc(sizeof(sip_event_queue_link_t));   
    if (!node) {
        RPTERR("oom: node create error!!");
        od_mutex_unlock(&obj_ptr->evt_que_link.mux);
        return OD_ERROR;
    }
    
    memcpy(&node->evt_que, evt_que, sizeof(od_sip_event_queue));
    if (!obj_ptr->evt_que_link.que) {
        node->next = NULL;
    }else {
        node->next = obj_ptr->evt_que_link.que;
    }
    obj_ptr->evt_que_link.num++;
    obj_ptr->evt_que_link.que = node;
    od_mutex_unlock(&obj_ptr->evt_que_link.mux);

    return OD_OK;
}

void od_sip_evt_distrb_remove(od_sip_event_queue *evt_que)
{
    sip_event_queue_link_t **node, *tmp;
    
    OD_SIP_ASSERT(evt_que && obj_ptr);

    od_mutex_lock(&obj_ptr->evt_que_link.mux); 
    node = &(obj_ptr->evt_que_link.que);
    while(*node) {
        if ((*node)->evt_que.tsk_id == evt_que->tsk_id
             && (*node)->evt_que.queue_type == evt_que->queue_type) {
            tmp = *node;
            *node = (*node)->next;
            
            free(tmp);
            obj_ptr->evt_que_link.num--;
            break;
        }

        node = &((*node)->next);
    }
    od_mutex_unlock(&obj_ptr->evt_que_link.mux);
}

static int sip_evt_dstrb_event_distribute(od_sip_evt_dstrb_obj *obj, 
                                             eXosip_event_t *event)
{
    sip_event_queue_link_t *node = obj->evt_que_link.que;

    od_mutex_lock(&obj->evt_que_link.mux);
    while(node) {
        if (node->evt_que.queue_type == OD_SIP_EVT_QUEUE_TYPE_REGISTER_CLIENT) {
            if (*node->evt_que.obj_id == event->rid) {
                goto exit;
            }
        }

        if (node->evt_que.queue_type == OD_SIP_EVT_QUEUE_TYPE_INVITE) {
            if (*node->evt_que.obj_id == event->cid) {
                goto exit;
            }
        } 

        if (node->evt_que.queue_type == OD_SIP_EVT_QUEUE_TYPE_HANDLE_EVENT) {
            if (*node->evt_que.obj_id == event->cid 
                 || event->type == EXOSIP_CALL_INVITE) {
                goto exit;
            }
        }

        if (node->evt_que.queue_type == OD_SIP_EVT_QUEUE_TYPE_REGISTER_SERVER) {
            if (event->request != NULL) {
                if (event->type == EXOSIP_MESSAGE_NEW
                    && MSG_IS_REGISTER(event->request)) {
                    RPTDBG("get REGISTER event!!");
                    goto exit;
                }
            }
        }
        
        node = node->next;
    }

    node = obj->evt_que_link.que;
    while(node) {
        if (node->evt_que.queue_type == OD_SIP_EVT_QUEUE_TYPE_OTHER) {
            goto exit;
        }
        node = node->next;
    }

    RPTERR("!!!Event lost!!error!");
    eXosip_event_free(event);
    od_mutex_unlock(&obj_ptr->evt_que_link.mux);
    return OD_ERROR;

exit:
    if (node && node->evt_que.g_event_pipe)
        pipeline_put(node->evt_que.g_event_pipe, event);
    
    od_mutex_unlock(&obj_ptr->evt_que_link.mux);
    return OD_OK;
}

static int sip_evt_dstrb_start_stop(od_sip_evt_dstrb_obj *obj)
{
    obj->ctx = od_sip_lib_start();
    OD_SIP_ASSERT_RETURN(obj->ctx, OD_EFAULT);

    return OD_OK;
}

static void sip_evt_dstrb_start_stop_delete(od_sip_evt_dstrb_obj *obj)
{
    od_sip_lib_stop();
}


static int sip_evt_dstrb_process(od_sip_evt_dstrb_obj *obj)
{
    eXosip_event_t *event = NULL;
    
    /*从exosip底层获取sip事件*/
    event = eXosip_event_wait(obj->ctx->ex_ctx, 0 ,100);
    if(event == NULL)
    {
        od_msleep(50);
        return OD_OK;
    }

    /*事件分发*/
    RPTDBG("get:[%s]\n", event->textinfo);
    return sip_evt_dstrb_event_distribute(obj, event);
}


od_sip_event_distributor_handle od_sip_event_distributor_create(od_sip_event_distributor_static_params *static_params,
                                                                   od_sip_event_distributor_dynamic_params *dynamic_params)
{
    od_sip_evt_dstrb_obj *obj = NULL;

    OD_SIP_ASSERT_RETURN(static_params, NULL);
    OD_SIP_ASSERT_RETURN(static_params->task_name, NULL);
    
    /* create and initialize task object */
    obj = od_task_create((char *)static_params->task_name, sizeof(od_sip_evt_dstrb_obj));
    if(obj == NULL)
    {
        RPTERR(" create NULL pointer");
        return NULL;
    }
    
    obj->tab = NULL;
    obj->params_nums = 0;
    obj->evt_que_link.num = 0;
    obj->evt_que_link.que = NULL;
    if (od_mutex_init(&obj->evt_que_link.mux) != OD_OK) {
        RPTERR(" init od_sip_event_distrb mux error!");
        return NULL;
    }

    obj->stack_size = SIP_EVENT_DISTRIBUTOR_TSK_STACK_SIZE;
    obj->pf_start_stop  = (void *)sip_evt_dstrb_start_stop;
    obj->pf_malloc_free = NULL;
    obj->pf_rt_set = NULL;
    obj->pf_process     = (void *)sip_evt_dstrb_process;
    obj->pf_malloc_free_delete = NULL;
    obj->pf_start_stop_delete = (void *)sip_evt_dstrb_start_stop_delete;

    RPTDBG("create success");
    obj_ptr = obj;
    return (od_sip_event_distributor_handle)obj;   
}


/*_*/

